﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using System.Threading;

using XmlBrowser;
using DbSharp.Utils;
using DbSharp.Framework.CaseFile.Parser;
using DbSharp.GuiRunner.Properties;
using DbSharp.Framework.CaseFile;

using DbSharp.GuiRunner.ViewItems;
using DbSharp.Framework.TestEngine;
using DbSharp.GuiRunner.View;
using DbSharp.UIControls.ImageComboBox;
using DbSharp.Framework.ReleaseManage;
using DbSharp.Utils.IO;
using DbSharp.Framework;




namespace DbSharp.GuiRunner.UI
{
    partial class FormTestConsole : Form
    {
        private readonly int Max_Saved_TestFile_Count = 20;
        private XmlBrowser.XmlBrowser m_XmlSectionWebBrowser2;
        private CaseFileParser m_TestcaseParser;
        private CaseFileNavigator m_FileNavigator;
        private CaseFileLoader m_TestLoader;
        private List<ImageComboItem> m_ListImageComboItem = new List<ImageComboItem>();
        private string m_TestcaseFile;
        private FileSystemWatcher m_TestcaseFileWatchdog = new FileSystemWatcher();
        private bool m_NeedReloadTestCaseFile;
        private TestReport m_TestReport = new TestReport();
        private string m_Xml_Header = @"<?xml version=""1.0"" encoding=""utf-8"" ?>";
        private int m_ElapsedSeconds;
        //perfcase view items
        private BindingList<PerfCaseViewItem> m_ListPerfTestCaseVI = new BindingList<PerfCaseViewItem>();
        //unitcase view items
        private BindingList<UnitCaseViewItem> m_ListUnitTestCaseVI = new BindingList<UnitCaseViewItem>();

     
        private void CreateUIXmlBrowser()
        {
            this.m_XmlSectionWebBrowser2 = new XmlBrowser.XmlBrowser();
            this.m_XmlSectionWebBrowser2.XmlFont = new Font("Tahoma", 8.25f);
            this.m_XmlSectionWebBrowser2.Dock = System.Windows.Forms.DockStyle.Fill;
            this.m_XmlSectionWebBrowser2.Location = new System.Drawing.Point(3, 16);
            this.m_XmlSectionWebBrowser2.Name = "m_XmlSectionWebBrowser2";
            this.m_XmlSectionWebBrowser2.Size = new System.Drawing.Size(400, 161);
            this.m_XmlSectionWebBrowser2.TabIndex = 1;
            this.toolStripLabel_WebBrowserCopyHint.Visible = false;
            this.panel_XmlSectionView.Controls.Add(this.m_XmlSectionWebBrowser2);
        }

        public FormTestConsole()
        {
            InitializeComponent();
            CreateUIXmlBrowser();
 
            timerTestElapsed.Enabled = false;
            perfTestsGrid.AutoGenerateColumns = false;
            unitTestsGrid.AutoGenerateColumns = false;
            perfTestsGrid.DataSource = m_ListPerfTestCaseVI;
            unitTestsGrid.DataSource = m_ListUnitTestCaseVI;
        }


        public string StartupTestcaseFile { get; set; }

        public TestRunScope AutoRunScope { get; set; }


        private void SaveIntoRecentTestCaseList(string testCaseFile)
        {
            #region Save to config file

            if (Settings.Default.RecentTestCaseFiles.Contains(testCaseFile))
            {
                Settings.Default.RecentTestCaseFiles.Remove(testCaseFile);
            }
            Settings.Default.RecentTestCaseFiles.Add(testCaseFile);

            //only save at most 
            while (Settings.Default.RecentTestCaseFiles.Count > Max_Saved_TestFile_Count)
            {
                Settings.Default.RecentTestCaseFiles.RemoveAt(Settings.Default.RecentTestCaseFiles.Count - 1);
            }
            Settings.Default.Save();

            #endregion

            #region repaint the UI
            if (toolStripComboBoxTestcaseFile.Items.Contains(testCaseFile))
            {
                toolStripComboBoxTestcaseFile.Items.Remove(testCaseFile);
            }
            toolStripComboBoxTestcaseFile.Items.Insert(0, testCaseFile);
            toolStripComboBoxTestcaseFile.Text = testCaseFile;
            #endregion
        }


        private void LoadRecentTestCaseFiles()
        {
            toolStripComboBoxTestcaseFile.Items.Clear();

            //Most recent file is the top 1 on the list
            foreach (string testConfigFile in Settings.Default.RecentTestCaseFiles)
            {
                if (File.Exists(testConfigFile))
                    toolStripComboBoxTestcaseFile.Items.Insert(0, testConfigFile);
            }

            if (toolStripComboBoxTestcaseFile.Items.Count > 0)
                toolStripComboBoxTestcaseFile.Text = toolStripComboBoxTestcaseFile.Items[0].ToString();
        }


        private void LoadPerfTestCasesIntoGrid()
        {
            m_ListPerfTestCaseVI.Clear();

            var listTestRunner = m_TestLoader.LoadPerfCaseRunners();
            foreach (var runner in listTestRunner)
            {
                var viewItem = new PerfCaseViewItem(testStateImages, exportFlagImageList, runner);
                m_ListPerfTestCaseVI.Add(viewItem);
            }
        }


        private void LoadUnitTestCasesIntoGrid()
        {
            m_ListUnitTestCaseVI.Clear();
            var listTestRunner = m_TestLoader.LoadUnitCaseRunners();
            foreach (var runner in listTestRunner)
            {
                var viewItem = new UnitCaseViewItem(testStateImages, exportFlagImageList, runner);
                m_ListUnitTestCaseVI.Add(viewItem);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="testcaseFile"></param>
        /// <returns>true when load successful</returns>
        private bool LoadTestcaseFile(string testcaseFile)
        {
            Trace.WriteLine("step 2_1:" + DateTime.Now.Ticks);
            ICaseFileLoadedNotify notifier = new GuiCaseFileLoadedNotifier(outputRichTextBox);
            Trace.WriteLine("step 2_2:" + DateTime.Now.Ticks);
            m_TestcaseParser = new CaseFileParser(notifier, testcaseFile);
            Trace.WriteLine("step 2_3:" + DateTime.Now.Ticks);
            if (m_TestcaseParser.XmlIsValid == false)
            {
                m_TestcaseParser = null;
                m_FileNavigator = null;
                //string errorFmt = "File '{0}' is not valid, please make sure it must follow the given schema.";
                //MessageBox.Show(string.Format(errorFmt, testcaseFile), "Info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            else
            {
                m_TestcaseFile = testcaseFile;
                Trace.WriteLine("step 2_4:" + DateTime.Now.Ticks);
                m_TestLoader = new CaseFileLoader(m_TestcaseParser);
                m_FileNavigator = m_TestcaseParser.FileNavigator;
                Trace.WriteLine("step 2_5:" + DateTime.Now.Ticks);

                m_TestcaseFileWatchdog.Path = Path.GetDirectoryName(m_TestcaseFile);
                m_TestcaseFileWatchdog.Filter = Path.GetFileName(m_TestcaseFile);

                m_TestcaseFileWatchdog.EnableRaisingEvents = false;
                m_TestcaseFileWatchdog.Changed -= new FileSystemEventHandler(m_TestcaseFileWatchdog_Changed);
                m_TestcaseFileWatchdog.Changed += new FileSystemEventHandler(m_TestcaseFileWatchdog_Changed);
                m_TestcaseFileWatchdog.EnableRaisingEvents = true;
                return true;
            }
        }




        private void ShowDialogToReloadFile()
        {
            string messageFmt = "File '{0}' has been changed. Reload it or not?";
            string message = string.Format(messageFmt, m_TestcaseFile);
            m_NeedReloadTestCaseFile = false;
            var ret = MessageBox.Show(message, "GUI Runer Info", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (ret == DialogResult.Yes)
                ReloadTestcaseFile(m_TestcaseFile);
        }


        private void m_TestcaseFileWatchdog_Changed(object sender, FileSystemEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Name))
                return;

            if (string.Equals(e.FullPath, m_TestcaseFile, StringComparison.OrdinalIgnoreCase) == false)
                return;

            if (e.ChangeType == WatcherChangeTypes.Changed)
            {
                m_NeedReloadTestCaseFile = true;

                if (RuntimeInfo.GetInstance().TestInProcess == false)
                {
                    //to switch to main UI thread 
                    this.Invoke(new Action(ShowDialogToReloadFile));
                }
            }
        }


        private void LoadObjectInspectorItems2()
        {
            //load image combobox 
            if (m_TestcaseParser == null)
                return;

            objectInpectorComboBox2.Items.Clear();
            m_ListImageComboItem.Clear();
            CaseFileObjectLoader caseFileObjectLoader = null;
            caseFileObjectLoader = new CaseFileObjectLoader(m_TestcaseParser);

            foreach (var item in caseFileObjectLoader.ListCaseFileObject)
            {
                ImageComboItem comboItem = new ImageComboItem(item.Name, (int)item.Type);
                comboItem.Tag = item;
                objectInpectorComboBox2.Items.Add(comboItem);
                m_ListImageComboItem.Add(comboItem);
            }
        }


        private void ClearObjectInspectorItems()
        {
            objectInpectorComboBox2.Items.Clear();
        }


        /// <summary>
        /// initialize the form after one test file loaded
        /// </summary>
        /// <param name="testcaseFile"></param>
        /// <returns>true when test file is valid, otherwise false</returns>
        private bool ReloadTestcaseFile(string testcaseFile)
        {
            FinalizeTestStatus(false);

            Trace.WriteLine("step 0:" + DateTime.Now.Ticks);

            m_ListPerfTestCaseVI.Clear();
            m_ListUnitTestCaseVI.Clear();
            objectInpectorComboBox2.SelectedIndex = -1;
            ClearObjectInspectorItems();

            Trace.WriteLine("step 1:" + DateTime.Now.Ticks);

            Trace.WriteLine("step 2:" + DateTime.Now.Ticks);
            bool validCaseFile = LoadTestcaseFile(testcaseFile);
            if (validCaseFile == false)
                return false;


            Trace.WriteLine("step 3:" + DateTime.Now.Ticks);
            SaveIntoRecentTestCaseList(testcaseFile);
            LoadObjectInspectorItems2();

            Trace.WriteLine("step 4:" + DateTime.Now.Ticks);
            //make sure order of calling LoadUnitTestCasesIntoGrid() and LoadPerfTestCasesIntoGrid()
            if (testGridTabControl.SelectedTab == perfGridTabPage)
            {
                Trace.WriteLine("step 4_1:" + DateTime.Now.Ticks);
                LoadUnitTestCasesIntoGrid();
                Trace.WriteLine("step 4_1_2:" + DateTime.Now.Ticks);
                LoadPerfTestCasesIntoGrid();
            }
            else
            {
                Trace.WriteLine("step 4_2:" + DateTime.Now.Ticks);
                LoadPerfTestCasesIntoGrid();
                Trace.WriteLine("step 4_2_2:" + DateTime.Now.Ticks);
                LoadUnitTestCasesIntoGrid();
            }
            return true;
        }


        private void perfTestsGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;
            if (perfTestsGrid.CurrentRow == null)
                return;

            PerfCaseViewItem selectedRow = (PerfCaseViewItem)perfTestsGrid.CurrentRow.DataBoundItem;
            if (selectedRow == null)
                return;

            if (e.ColumnIndex == 7)
            {
                using (var form = new FormTestResult())
                {
                    form.TestRunner = selectedRow.TestRunner;
                    form.ShowDialog();
                }
            }
        }

        private void unitTestsGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;
            if (unitTestsGrid.CurrentRow == null)
                return;

            UnitCaseViewItem selectedRow = (UnitCaseViewItem)unitTestsGrid.CurrentRow.DataBoundItem;
            if (selectedRow == null)
                return;
            if (e.ColumnIndex == 5)
            {
                using (var form = new FormTestResult())
                {

                    form.TestRunner = selectedRow.TestRunner;
                    form.ShowDialog();
                }
            }
            else if (e.ColumnIndex == 6)
            {
                ShowDiff(selectedRow.TestRunner);
            }
        }

        private void ShowDiff(UnitTestRunner unitTestRunner)
        {
            if (unitTestRunner == null)
                return;

            if (unitTestRunner.CaseExecuteResult.TestState == CaseTestState.NotRun)
            {
                MessageBox.Show("Please run or export first.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            using (var form = new FormDiff())
            {
                ITestCaseStatusNotify statusNotifier;
                statusNotifier = new GuiTestStatusNotifier(outputRichTextBox, unitTestsGrid, false);
                form.TestStatusNotify = statusNotifier;
                form.UnitTestRunner = unitTestRunner;
                form.ShowDialog();
            }
        }

        private bool IsSameCaseFileObject(CaseFileObject item1, CaseFileObject item2)
        {
            if ((item1 == null) || (item2 == null))
                return false;
            if ((item1.Name == item2.Name)
                       && (item1.Type == item2.Type))
                return true;
            else
                return false;
        }

        private void SetActiveItemForInspectorCombobox2(CaseFileObject selectedItem)
        {
            if (selectedItem == null)
                return;
            if (objectInpectorComboBox2.SelectedItem != null)
            {
                var selectedInComboxItem = (ImageComboItem)objectInpectorComboBox2.SelectedItem;
                if (IsSameCaseFileObject(selectedItem, (CaseFileObject)selectedInComboxItem.Tag))
                    return;
            }

            ImageComboItem futureSelectedItemInCombo = null;
            foreach (ImageComboItem item in objectInpectorComboBox2.Items)
            {
                if (IsSameCaseFileObject((CaseFileObject)item.Tag, selectedItem))
                {
                    futureSelectedItemInCombo = item;
                    break;
                }
            }
            if (futureSelectedItemInCombo != null)
                objectInpectorComboBox2.SelectedItem = futureSelectedItemInCombo;
        }

        private void unitTestsGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            UnitCaseViewItem selectedRow = (UnitCaseViewItem)unitTestsGrid.CurrentRow.DataBoundItem;
            if (selectedRow == null)
                return;
            CaseFileObject selectedItem = new CaseFileObject();
            selectedItem.Name = selectedRow.CaseName;
            selectedItem.Type = CaseFileObjectType.UnitTest;
            Trace.WriteLine("webBrowser nav:step 1:" + DateTime.Now.Ticks);
            SetActiveItemForInspectorCombobox2(selectedItem);
            Trace.WriteLine("webBrowser nav:step 4:" + DateTime.Now.Ticks);
        }

        private void perfTestsGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            PerfCaseViewItem selectedRow = (PerfCaseViewItem)perfTestsGrid.CurrentRow.DataBoundItem;
            if (selectedRow == null)
                return;
            CaseFileObject selectedItem = new CaseFileObject();
            selectedItem.Name = selectedRow.CaseName;
            selectedItem.Type = CaseFileObjectType.PerfTest;
            SetActiveItemForInspectorCombobox2(selectedItem);
        }

        private void stopToolStripButton_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                RuntimeInfo.GetInstance().Interrupted = true;
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;

            using (FormAboutBox aboutForm = new FormAboutBox())
            {
                aboutForm.ShowDialog();
            }
        }


        private void helpDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProcessLauncher.CallWindowsApp(VendorInfo.OfficialOnlineTutorialUrl, false);
        }


     

        private void officialWebsiteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProcessLauncher.CallWindowsApp(VendorInfo.OfficialWebsite, false);
        }

 

        private void openCaseFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;

            try
            {
                openTestFileDialog.InitialDirectory = Path.GetDirectoryName(toolStripComboBoxTestcaseFile.Text);
            }
            catch { /*suppress all exceptions*/ }

            openTestFileDialog.Title = "Open one test case file";
            openTestFileDialog.FileName = string.Empty;
            if (DialogResult.OK == openTestFileDialog.ShowDialog())
            {
                toolStripComboBoxTestcaseFile.Text = openTestFileDialog.FileName;
                ReloadTestcaseFile(openTestFileDialog.FileName);
            }
        }

        private void loadFileToolStripButton_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;

            string fileName = toolStripComboBoxTestcaseFile.Text;
            ReloadTestcaseFile(fileName);
        }


 
        /// <summary>
        /// suppress MouseWheel scroll to change the selectedItem of combobox, 
        /// to prevent the WebBrowser control switch another url frequently.  
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectInpectorComboBox_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ((HandledMouseEventArgs)e).Handled = true;
        }



        /// <summary>
        /// suppress MouseWheel scroll to change the selectedItem of combobox, 
        /// to prevent the WebBrowser control switch another url frequently.  
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectInpectorComboBox2_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ((HandledMouseEventArgs)e).Handled = true;
        }


        private void FormTestConsole_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void FormTestConsole_DragDrop(object sender, DragEventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;

            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] filenames = (string[])e.Data.GetData(DataFormats.FileDrop);
                toolStripComboBoxTestcaseFile.Text = filenames[0];
                string fileName = toolStripComboBoxTestcaseFile.Text;
                ReloadTestcaseFile(fileName);
            }
        }
 

        private void FormTestConsole_Load(object sender, EventArgs e)
        {
            FinalizeTestStatus(false);
            LoadRecentTestCaseFiles();

            if (string.IsNullOrEmpty(this.StartupTestcaseFile) == false)
            {
                toolStripComboBoxTestcaseFile.Text = StartupTestcaseFile;

                //load the case file
                string fileName = toolStripComboBoxTestcaseFile.Text;
                bool testFileIsValid = ReloadTestcaseFile(fileName);

                //Run test cases
                if (testFileIsValid)
                    RunCaseFileWithLog(AutoRunScope);
            }

        }

        private void OpenFilebyIEToolStripButton_Click(object sender, EventArgs e)
        {
            string fileName = toolStripComboBoxTestcaseFile.Text;
            if (File.Exists(fileName))
                ProcessLauncher.CallWindowsApp(fileName, false);
        }

        private void toolStripButtonOpenByNotepad_Click(object sender, EventArgs e)
        {
            string fileName = toolStripComboBoxTestcaseFile.Text;
            if (File.Exists(fileName))
                ProcessLauncher.OpenFileByApp("notepad", fileName, false);
        }

        private void toolStripButtonOpenByOS_Click(object sender, EventArgs e)
        {
            string fileName = toolStripComboBoxTestcaseFile.Text;
            if (File.Exists(fileName))
                ProcessLauncher.OpenFileByOS(fileName, false);
        }


        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess == false)
                Close();
        }


        private void objectInpectorComboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_FileNavigator == null)
                return;
            if (objectInpectorComboBox2.SelectedItem == null)
            {
                m_XmlSectionWebBrowser2.Navigate(m_Xml_Header);
                return;
            }

            ImageComboItem selectedComboItem = (ImageComboItem)objectInpectorComboBox2.SelectedItem;

            CaseFileObject caseFileObject = (CaseFileObject)selectedComboItem.Tag;
            string name = caseFileObject.Name;
            XElement section;
            string xmlText = string.Empty;
            switch (caseFileObject.Type)
            {
                case CaseFileObjectType.DbConnection:
                    section = m_FileNavigator.SelectDbConn(name);
                    break;
                case CaseFileObjectType.PerfTest:
                    section = m_FileNavigator.SelectPerfTestCase(name);
                    break;
                case CaseFileObjectType.UnitTest:
                    section = m_FileNavigator.SelectUnitTestCase(name);
                    break;
                case CaseFileObjectType.Statement:
                    section = m_FileNavigator.SelectSqlDeclaration(name);
                    if (section == null)
                    {
                        //maybe this object is procDeclaration
                        section = m_FileNavigator.SelectProcedureDeclaration(name);
                    }
                    break;
                case CaseFileObjectType.GlabalSetting:
                    section = m_FileNavigator.SelectGlobalSetting();
                    break;
                case CaseFileObjectType.ProcDeclarations:
                    section = m_FileNavigator.SelectProcDeclsRoot();
                    break;
                case CaseFileObjectType.SqlDeclarations:
                    section = m_FileNavigator.SelectSqlDeclsRoot();
                    break;
                case CaseFileObjectType.EntireFile:
                    section = m_FileNavigator.SelectRootElement();
                    break;
                default:
                    section = null;
                    break;
            }
            xmlText = (section == null) ? string.Empty : section.ToString();

            if (string.IsNullOrEmpty(xmlText) == false)
                m_XmlSectionWebBrowser2.Navigate(xmlText);
        }
 

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;
            using (var form = new FormOptions())
            {
                form.ShowDialog();
            }
        }



        private void timerTestElapsed_Tick(object sender, EventArgs e)
        {
            m_ElapsedSeconds++;
            elapsedTimeToolStripStatusLabel.Text = "Elapsed time: " + m_ElapsedSeconds;
        }


        #region Background thread
        private void EnableToolButtons(bool enabled)
        {
            runToolStripButton.Enabled = enabled;
            runSelectedToolStripMenuItem.Enabled = enabled;

            runGridToolStripButton.Enabled = enabled;
            runGridToolStripMenuItem.Enabled = enabled;

            exportToolStripSplitButton.Enabled = enabled;
            exportToolStripMenuItem.Enabled = enabled;

            freshExport2ToolStripMenuItem.Enabled = enabled;
            freshExportToolStripMenuItem.Enabled = enabled;

            freshExportGrid2ToolStripMenuItem.Enabled = enabled;
            freshExportGridToolStripMenuItem.Enabled = enabled;

            exportGridToolStripSplitButton.Enabled = enabled;
            exportGridToolStripMenuItem.Enabled = enabled;

            runCaseFileToolStripButton.Enabled = enabled;
            runCaseFiletoolStripMenuItem2.Enabled = enabled;

            stopToolStripButton.Enabled = !enabled;
            stopToolStripMenuItem.Enabled = !enabled; ;
        }

        private void InitializeTestStatus()
        {
            RuntimeInfo.GetInstance().Interrupted = false;
            RuntimeInfo.GetInstance().TestInProcess = true;
            m_ElapsedSeconds = 0;
            timerTestElapsed.Enabled = true;
            progressbarToolStripDropDownButton.Visible = true;
            processBarStatusStrip.Visible = true;
            EnableToolButtons(false);

            #region Restore every test case into orginal image
            foreach (DataGridViewRow row in unitTestsGrid.Rows)
            {
                var viewItem = (UnitCaseViewItem)row.DataBoundItem;
                viewItem.State = CaseTestState.NotRun;
            }
            foreach (DataGridViewRow row in perfTestsGrid.Rows)
            {
                var viewItem = (PerfCaseViewItem)row.DataBoundItem;
                viewItem.State = CaseTestState.NotRun;
            }
            #endregion

        }



        private void FinalizeTestStatus(bool testFinished)
        {
            if (this.InvokeRequired)
                this.Invoke(new Action<bool>(FinalizeTestStatus), testFinished);
            else
            {
                RuntimeInfo.GetInstance().Interrupted = false;
                RuntimeInfo.GetInstance().TestInProcess = false;
                EnableToolButtons(true);
                timerTestElapsed.Enabled = false;
                progressbarToolStripDropDownButton.Visible = false;

                if (testFinished == false)
                {
                    elapsedTimeToolStripStatusLabel.Text = "Ready";
                    perfGridTabPage.ImageIndex = (int)CaseTestState.NotRun;
                    unitGridTabPage.ImageIndex = (int)CaseTestState.NotRun;
                }


                #region Show test report info
                if (testFinished == true)
                {
                    m_TestReport.EndReport();
                    ITestReportNotify testReportNotifier = new GuiTestReportNotifier(this.outputRichTextBox);
                    testReportNotifier.UpdateStatus(m_TestReport);

                    perfGridTabPage.ImageIndex = (int)m_TestReport.GetPerfTestsOverallTestState();
                    unitGridTabPage.ImageIndex = (int)m_TestReport.GetUnitTestsOverallTestState();
                }
                #endregion

                if (testFinished)
                {
                    //reload the testcase file 
                    if (m_NeedReloadTestCaseFile)
                    {
                        ShowDialogToReloadFile();
                    }
                }

            }
        }



        private void RunCurrentCase(CaseRunDirective runDirective)
        {
            List<TestRunnerParam> listTestRunnerParam;
            List<DataGridViewRow> listRows = new List<DataGridViewRow>();

            if (testGridTabControl.SelectedTab == perfGridTabPage)
            {
                if (perfTestsGrid.CurrentRow != null)
                    listRows.Add(perfTestsGrid.CurrentRow);
                listTestRunnerParam = CollectPerfTestRunnersParam(listRows, runDirective);
            }
            else
            {
                if (unitTestsGrid.CurrentRow != null)
                    listRows.Add(unitTestsGrid.CurrentRow);
                listTestRunnerParam = CollectUnitTestRunnersParam(listRows, runDirective);
            }

            PerformTestCases(listTestRunnerParam);
        }



        private void RunAllCasesInTestFile(CaseRunDirective runDirective, TestRunScope runScope)
        {
            List<TestRunnerParam> listTestRunnerParam = new List<TestRunnerParam>();
            List<TestRunnerParam> listTestRunnerParam1 = null;
            List<TestRunnerParam> listTestRunnerParam2 = null;
            List<DataGridViewRow> listRows = new List<DataGridViewRow>();

            if ((runScope == TestRunScope.UnitTest) || (runScope == TestRunScope.All))
            {
                listRows.Clear();
                foreach (DataGridViewRow row in unitTestsGrid.Rows)
                {
                    listRows.Add(row);
                }
                listTestRunnerParam1 = CollectUnitTestRunnersParam(listRows, runDirective);
            }

            if ((runScope == TestRunScope.PerfTest) || (runScope == TestRunScope.All))
            {
                listRows.Clear();
                foreach (DataGridViewRow row in perfTestsGrid.Rows)
                {
                    listRows.Add(row);
                }
                listTestRunnerParam2 = CollectPerfTestRunnersParam(listRows, runDirective);
            }

            if (listTestRunnerParam1 != null)
            {
                foreach (var item in listTestRunnerParam1)
                    listTestRunnerParam.Add(item);
            }
            if (listTestRunnerParam2 != null)
            {
                foreach (var item in listTestRunnerParam2)
                    listTestRunnerParam.Add(item);
            }
            PerformTestCases(listTestRunnerParam);
        }



        /// <summary>
        /// Return brief info of row in perf test grid 
        /// </summary>
        /// <param name="listRows"></param>
        /// <returns></returns>
        private List<string> GetPerfCasesBriefInfo(List<DataGridViewRow> listRows)
        {
            List<string> result = new List<string>();
            foreach (DataGridViewRow row in listRows)
            {
                PerfCaseViewItem viewItem = (PerfCaseViewItem)row.DataBoundItem;
                StringBuilder brief = new StringBuilder();

                brief.Append("CaseName=").Append(viewItem.CaseName).Append(", ");
                brief.Append("TestState=").Append(viewItem.State).Append(", ");
                brief.Append("ExecutionTime=").Append(viewItem.ExecutionTime).Append(", ");
                brief.Append("FetchTime=").Append(viewItem.FetchTime).Append(", ");
                brief.Append("TotalTime=").Append(viewItem.TotalTime);
                result.Add(brief.ToString());
            }
            return result;
        }


        /// <summary>
        /// Return brief info of row in unit test grid 
        /// </summary>
        /// <param name="listRows"></param>
        /// <returns></returns>
        private List<string> GetUnitCasesBriefInfo(List<DataGridViewRow> listRows)
        {
            List<string> result = new List<string>();
            foreach (DataGridViewRow row in listRows)
            {
                UnitCaseViewItem viewItem = (UnitCaseViewItem)row.DataBoundItem;
                StringBuilder brief = new StringBuilder();

                brief.Append("CaseName=").Append(viewItem.CaseName).Append(", ");
                brief.Append("TestState=").Append(viewItem.State).Append(", ");
                brief.Append("Assertion=").Append(viewItem.AssertionText);
                result.Add(brief.ToString());
            }
            return result;
        }




        private List<TestRunnerParam> CollectPerfTestRunnersParam(List<DataGridViewRow> listRows, CaseRunDirective runDirective)
        {
            bool willExportData = runDirective.WillExportData;
            ITestCaseStatusNotify statusNotifier;
            statusNotifier = new GuiTestStatusNotifier(outputRichTextBox, perfTestsGrid, true);

            List<TestRunnerParam> listParam = new List<TestRunnerParam>();
            foreach (DataGridViewRow row in listRows)
            {
                CaseRunType runType;
                if (willExportData)
                    runType = CaseRunType.ExportXml;
                else
                    runType = CaseRunType.Test;

                PerfCaseViewItem viewItem = (PerfCaseViewItem)row.DataBoundItem;
                TestRunnerParam param = new TestRunnerParam()
                {
                    RunType = runType,
                    StatusNotifier = statusNotifier,
                    TestRunner = viewItem.TestRunner
                };
                listParam.Add(param);
            }

            return listParam;
        }




        private List<TestRunnerParam> CollectUnitTestRunnersParam(List<DataGridViewRow> listRows, CaseRunDirective runDirective)
        {
            bool willExportData = runDirective.WillExportData;
            bool forceRunBeforeExport = runDirective.ForceRunBeforeExport;
            ITestCaseStatusNotify statusNotifier;
            statusNotifier = new GuiTestStatusNotifier(outputRichTextBox, unitTestsGrid, false);

            List<TestRunnerParam> listParam = new List<TestRunnerParam>();
            foreach (DataGridViewRow row in listRows)
            {
                CaseRunType runType;
                UnitCaseViewItem viewItem = (UnitCaseViewItem)row.DataBoundItem;
                if (willExportData)
                {
                    viewItem.TestRunner.ForceRunBeforeExport = forceRunBeforeExport;
                    runType = CaseRunType.ExportXml;
                }
                else
                {
                    runType = CaseRunType.Test;
                }

                TestRunnerParam param = new TestRunnerParam()
                {
                    RunType = runType,
                    StatusNotifier = statusNotifier,
                    TestRunner = viewItem.TestRunner
                };
                listParam.Add(param);
            }

            return listParam;
        }




        private void PerformTestCases(List<TestRunnerParam> listParam)
        {
            m_TestReport.BeginReport();

            #region Syn run TestCase
            //foreach (var param in listParam)
            //{
            //    RunCase(param);
            //}
            #endregion

            #region Asyn run Testcase
            Action action = () =>
            {
                foreach (var param in listParam)
                {
                    RunCase(param);
                }
            };
            IAsyncResult ar = action.BeginInvoke(
                (r) =>
                {
                    ((Action)r.AsyncState).EndInvoke(r);
                    FinalizeTestStatus(true);
                }, action);

            #endregion

        }

        class TestRunnerParam
        {
            public CaseRunType RunType { get; set; }
            public ITestCaseStatusNotify StatusNotifier { get; set; }
            public TestRunnerBase TestRunner { get; set; }
        }


        private void RunCase(object obj)
        {
            TestRunnerParam para = (TestRunnerParam)obj;
            para.TestRunner.Run(para.RunType, para.StatusNotifier);
            m_TestReport.EndTestCase(para.TestRunner);
        }


        private void ExecuteTests(Action action)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;

            InitializeTestStatus();
            if (action != null)
                action();
        }


        #endregion Background thread


        private void InvokeRunCurrentCase()
        {
            ExecuteTests(() =>
            {
                CaseRunDirective runDirective = new CaseRunDirective()
                {
                    WillExportData = false,
                    //force run db statement again
                    ForceRunBeforeExport = true
                };
                RunCurrentCase(runDirective);
            });
        }

        private void runToolStripButton_Click(object sender, EventArgs e)
        {
            InvokeRunCurrentCase();
        }


        private void copyCaseToClipboardMenuItem_Click(object sender, EventArgs e)
        {
            List<string> listBrief;

            List<DataGridViewRow> listRows = new List<DataGridViewRow>();
            if (testGridTabControl.SelectedTab == perfGridTabPage)
            {
                if (perfTestsGrid.CurrentRow != null)
                    listRows.Add(perfTestsGrid.CurrentRow);
                listBrief = GetPerfCasesBriefInfo(listRows);
            }
            else
            {
                if (unitTestsGrid.CurrentRow != null)
                    listRows.Add(unitTestsGrid.CurrentRow);
                listBrief = GetUnitCasesBriefInfo(listRows);
            }

            CopyCasesBriefToClipboard(listBrief);
        }


        private void CopyCasesBriefToClipboard(List<string> listBrief)
        {
            if (listBrief == null)
                return;

            StringBuilder context = new StringBuilder();
            foreach (string brief in listBrief)
            {
                context.AppendLine(brief);
            }
            try
            {
                Clipboard.SetDataObject(context.ToString(), true);
                //Clipboard.Clear();
                //Clipboard.SetText(context.ToString());
            }
            catch (Exception ex)
            {
                string errorMsg = ex.Message + Environment.NewLine + "Please try later. ";
                MessageBox.Show(errorMsg, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        private void copyGridToClipboardMenuItem_Click(object sender, EventArgs e)
        {
            List<string> listBrief;

            List<DataGridViewRow> listRows = new List<DataGridViewRow>();
            if (testGridTabControl.SelectedTab == perfGridTabPage)
            {
                foreach (DataGridViewRow row in perfTestsGrid.Rows)
                {
                    listRows.Add(row);
                }
                listBrief = GetPerfCasesBriefInfo(listRows);
            }
            else
            {
                foreach (DataGridViewRow row in unitTestsGrid.Rows)
                {
                    listRows.Add(row);
                }
                listBrief = GetUnitCasesBriefInfo(listRows);
            }

            CopyCasesBriefToClipboard(listBrief);
        }



        private void RunCaseFileWithLog(TestRunScope runScope)
        {
            ExecuteTests(() =>
            {
                CaseRunDirective runDirective = new CaseRunDirective()
                {
                    WillExportData = false,
                    //force run db statement again
                    ForceRunBeforeExport = true
                };

                RunAllCasesInTestFile(runDirective, runScope);
            });
        }



        private void runCaseFiletoolStripMenuItem2_Click(object sender, EventArgs e)
        {
            RunCaseFileWithLog(TestRunScope.All);
        }


        private void runGridToolStripButton_Click(object sender, EventArgs e)
        {
            TestRunScope runScope;
            if (testGridTabControl.SelectedTab == perfGridTabPage)
            {
                runScope = TestRunScope.PerfTest;
            }
            else
            {
                runScope = TestRunScope.UnitTest;
            }

            RunCaseFileWithLog(runScope);
        }

        private void exportToolStripSplitButton_ButtonClick(object sender, EventArgs e)
        {
            ExecuteTests(() =>
            {
                CaseRunDirective runDirective = new CaseRunDirective
                {
                    WillExportData = true,
                    ForceRunBeforeExport = false
                };
                RunCurrentCase(runDirective);
            });
        }

        private void exportGridToolStripSplitButton_ButtonClick(object sender, EventArgs e)
        {
            ExecuteTests(() =>
            {
                CaseRunDirective runDirective = new CaseRunDirective
                {
                    WillExportData = true,
                    ForceRunBeforeExport = false
                };

                TestRunScope runScope;
                if (testGridTabControl.SelectedTab == perfGridTabPage)
                {
                    runScope = TestRunScope.PerfTest;
                }
                else
                {
                    runScope = TestRunScope.UnitTest;
                }

                RunAllCasesInTestFile(runDirective, runScope);
            });
        }


        private void freshExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExecuteTests(() =>
            {
                CaseRunDirective runDirective = new CaseRunDirective
                {
                    WillExportData = true,
                    ForceRunBeforeExport = true
                };
                RunCurrentCase(runDirective);
            });
        }


        private void freshExportGridToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExecuteTests(() =>
            {
                CaseRunDirective runDirective = new CaseRunDirective
                {
                    WillExportData = true,
                    ForceRunBeforeExport = true
                };

                TestRunScope runScope;
                if (testGridTabControl.SelectedTab == perfGridTabPage)
                {
                    runScope = TestRunScope.PerfTest;
                }
                else
                {
                    runScope = TestRunScope.UnitTest;
                }

                RunAllCasesInTestFile(runDirective, runScope);
            });
        }

        private void AddQuickSearchItem(ImageComboItem comboItem)
        {
            var item = new ListViewItem();
            item.Text = comboItem.Text;
            item.Tag = comboItem.Tag;
            item.ImageIndex = comboItem.ImageIndex;
            listViewQuickSearchResult.Items.Add(item);
        }



        private void buttonQuickSearch_Click(object sender, EventArgs e)
        {
            listViewQuickSearchResult.Items.Clear();
            string objectName = textBoxSearchCaseObject.Text.Trim();
            if (string.IsNullOrEmpty(objectName))
                return;

            foreach (var comboItem in m_ListImageComboItem)
            {
                string comboItemText = ((CaseFileObject)(comboItem.Tag)).Name;
                if (checkBoxMatchWholeWord.Checked)
                {
                    if (string.Equals(comboItemText, objectName, StringComparison.OrdinalIgnoreCase))
                        AddQuickSearchItem(comboItem);
                }
                else
                {
                    if (comboItemText.IndexOf(objectName, StringComparison.OrdinalIgnoreCase) > -1)
                        AddQuickSearchItem(comboItem);
                }
            }
        }



        private void SortCaseFileObject(Action<List<ImageComboItem>> sortDelegate)
        {
            var selectedItem = objectInpectorComboBox2.SelectedItem;

            if (sortDelegate != null)
                sortDelegate(m_ListImageComboItem);

            objectInpectorComboBox2.Items.Clear();
            foreach (var comboItem in m_ListImageComboItem)
            {
                objectInpectorComboBox2.Items.Add(comboItem);
            }

            if (selectedItem != null)
                objectInpectorComboBox2.SelectedItem = selectedItem;
        }



        private void SortCaseFileObjectByName()
        {
            SortCaseFileObject((ImageComboItems) =>
            {
                ImageComboItems.Sort((item1, item2) => string.Compare(
                   ((CaseFileObject)(item1.Tag)).Name,
                   ((CaseFileObject)(item2.Tag)).Name,
                   StringComparison.OrdinalIgnoreCase));
            });
        }


        private void SortCaseFileObjectByCategory()
        {
            SortCaseFileObject((ImageComboItems) =>
            {
                ImageComboItems.Sort((item1, item2) =>
                {
                    int type1 = (int)(((CaseFileObject)(item1.Tag)).Type);
                    int type2 = (int)(((CaseFileObject)(item2.Tag)).Type);
                    return type1 - type2;
                });
            });
        }



        private void checkBoxSortByCategory_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxSortByCategory.Checked)
                SortCaseFileObjectByCategory();
            else
                SortCaseFileObjectByName();

        }



        private void textBoxSearchCaseObject_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)0xD)
                buttonQuickSearch_Click(sender, null);
        }

        private void FormTestConsole_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                e.Cancel = true;
        }

        private void openProjectFiletoolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;

        }

        private void reloadProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RuntimeInfo.GetInstance().TestInProcess)
                return;
        }


        private void locateInGridToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewQuickSearchResult.SelectedItems.Count == 0)
                return;

            var selectedListItem = listViewQuickSearchResult.SelectedItems[0];

            CaseFileObject selectObject = (CaseFileObject)(selectedListItem.Tag);
            CaseFileObjectType objectType = selectObject.Type;
            string selectObjectName = selectObject.Name;
            if (objectType == CaseFileObjectType.UnitTest)
            {
                testGridTabControl.SelectedTab = unitGridTabPage;
                unitTestsGrid.ClearSelection();
                foreach (DataGridViewRow row in unitTestsGrid.Rows)
                {
                    UnitCaseViewItem viewItem = (UnitCaseViewItem)row.DataBoundItem;
                    if (string.Equals(viewItem.CaseName, selectObjectName, StringComparison.Ordinal))
                    {
                        unitTestsGrid.CurrentCell = row.Cells[0];
                        unitTestsGrid.CurrentCell.Selected = true;
                        break;
                    }
                }
            }
            else if (objectType == CaseFileObjectType.PerfTest)
            {
                testGridTabControl.SelectedTab = perfGridTabPage;
                perfTestsGrid.ClearSelection();
                foreach (DataGridViewRow row in perfTestsGrid.Rows)
                {
                    PerfCaseViewItem viewItem = (PerfCaseViewItem)row.DataBoundItem;
                    if (string.Equals(viewItem.CaseName, selectObjectName, StringComparison.Ordinal))
                    {
                        perfTestsGrid.CurrentCell = row.Cells[0];
                        perfTestsGrid.CurrentCell.Selected = true;
                        break;
                    }
                }
            }
        }

        private void quickSearchResultContextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if (listViewQuickSearchResult.SelectedItems.Count == 0)
            {
                e.Cancel = true;
                return;
            }

            var selectedListItem = listViewQuickSearchResult.SelectedItems[0];
            CaseFileObjectType objectType = ((CaseFileObject)(selectedListItem.Tag)).Type;
            if ((objectType == CaseFileObjectType.UnitTest) || (objectType == CaseFileObjectType.PerfTest))
                locateInGridToolStripMenuItem.Enabled = true;
            else
                locateInGridToolStripMenuItem.Enabled = false;
        }

        private void listViewQuickSearchResult_DoubleClick(object sender, EventArgs e)
        {
            if (listViewQuickSearchResult.SelectedItems.Count == 0)
                return;

            var selectedListItem = listViewQuickSearchResult.SelectedItems[0];
            foreach (var comboItem in m_ListImageComboItem)
            {
                if (comboItem.Tag == selectedListItem.Tag)
                {
                    objectInpectorComboBox2.SelectedItem = comboItem;
                    break;
                }
            }
        }



        private void switchPerfGridToolStripMenuItem_Click(object sender, EventArgs e)
        {
            testGridTabControl.SelectedTab = perfGridTabPage;
        }

        private void switchUnitCaseGridToolStripMenuItem_Click(object sender, EventArgs e)
        {
            testGridTabControl.SelectedTab = unitGridTabPage;
        }

        private void perfTestsGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            InvokeRunCurrentCase();
        }

        private void zoom50toolStripMenuItem4_Click(object sender, EventArgs e)
        {
            int factor;
            //10..1000
            try
            {
                factor = int.Parse(((ToolStripMenuItem)sender).Tag.ToString());
            }
            catch
            {
                factor = 100;
            }
 
            ZoomXmlBrowser(factor);
 
        }

        private void ZoomXmlBrowser(int factor)
        {
            float fontSize = m_XmlSectionWebBrowser2.XmlFont.Size;
            fontSize = 8.25f * factor / 100;
            m_XmlSectionWebBrowser2.XmlFont = new Font(m_XmlSectionWebBrowser2.XmlFont.FontFamily, fontSize);

            try
            {
                m_XmlSectionWebBrowser2.Reload();
            }
            catch
            {
                //suppress all exceptions
            }
        }

  

        private void zoomInWebBrowsertoolStripButton2_Click(object sender, EventArgs e)
        {

            ZoomInXmlBrowser();
 
        }

        private void ZoomInXmlBrowser()
        {
            float fontSize = m_XmlSectionWebBrowser2.XmlFont.Size;
            if (fontSize <= 50)
                fontSize = fontSize + 1;
            m_XmlSectionWebBrowser2.XmlFont = new Font(m_XmlSectionWebBrowser2.XmlFont.FontFamily, fontSize);
            try
            {
                m_XmlSectionWebBrowser2.Reload();
            }
            catch
            {
                //suppress all exceptions
            }
        }

 

        private void zoomOutWebBrowsertoolStripButton_Click(object sender, EventArgs e)
        {
 
            ZoomOutXmlBrowser();
 
        }
 

        private void ZoomOutXmlBrowser()
        {
            float fontSize = m_XmlSectionWebBrowser2.XmlFont.Size;
            if (fontSize >= 5)
                fontSize = fontSize - 1;
            m_XmlSectionWebBrowser2.XmlFont = new Font(m_XmlSectionWebBrowser2.XmlFont.FontFamily, fontSize);

            try
            {
                m_XmlSectionWebBrowser2.Reload();
            }
            catch
            {
                //suppress all exceptions
            }
        }


    }
}
